#include "AReVi/arSystem.h"
#include "AReVi/Lib3D/viewer3D.h"
#include "AReVi/Lib3D/scene3D.h"
#include "AReVi/Shapes/mesh3D.h"
using namespace AReVi;

#include "manager.h"
#include "connector.h"
#include "awesomeMan.h"
#include "environment.h"
#include "city.h"

extern void registerAwesomeClasses(void);

class Controller : public ArObject {
public:
  AR_CLASS(Controller)
    AR_CONSTRUCTOR(Controller)
    
    protected:
    void _onKeyboard(const Renderer3D::KeyboardEvent & evt);
  
  ArRef<AwesomeMan> _element;
};

AR_CLASS_DEF(Controller, ArObject)

Controller::Controller(ArCW & arCW) : ArObject(arCW) {
  cout << "Creating AwesomeMan" << endl;
	//TEST : on ajoute une box dans l'environnement en local
  _element = AwesomeMan::NEW();
  _element->init();
  
  StlVector<StlString> actions = _element->getActions();
  for (unsigned int i = 0; i < actions.size(); i++) {
    cerr << "DEBUG: available action : " << actions[i] << endl;
  }
  
  Manager::getInstance()->getEnvironment()->addElement(_element);
  Manager::getInstance()->getRenderer()->addKeyboardCB(thisRef(), &Controller::_onKeyboard);
}

Controller::~Controller() {
}

void Controller::_onKeyboard(const Renderer3D::KeyboardEvent & evt) {
  double x, y, z;
  _element->getAngularAcc(x, y, z);
  if (evt.key == "Up" && evt.pressed) {
    if (evt.source->shiftPressed()) {
      _element->doAction("WalkStart");
      _element->doAction("FlyStart");
      _element->doAction("Fly");
      _element->setAcceleration(3.0);
      _element->setSpeedLimits(1.0, 10.0);
    }
    else {
      _element->doAction("WalkStart");
      _element->doAction("Walk");
      _element->setAcceleration(1.0);
      _element->setSpeedLimits(1.0, 30.0);
    }
  }
  if (evt.key == "Up" && !evt.pressed) {
    _element->setAcceleration(-2.0);
    if (_element->getLastAction() == "Walk") _element->doAction("WalkEnd");
    if (_element->getLastAction() == "Fly") {
      _element->doAction("FlyEnd");
      _element->doAction("WalkEnd");
    }
  }
  
  if (evt.key == " " && evt.pressed) {
    if (_element->getLastAction() == "Walk") _element->doAction("WalkEnd");
    if (_element->getLastAction() == "Fly") {
      _element->doAction("FlyEnd");
      _element->doAction("WalkEnd");
    }
    _element->doAction("BackFlip");
  }
  
  if (evt.key == "Left" && evt.pressed) {
    _element->setTurnCoeff(0.3);
  }
  if (evt.key == "Left" && !evt.pressed) {
    _element->setTurnCoeff(0.0);
  }
  if (evt.key == "Right" && evt.pressed) {
    _element->setTurnCoeff(-0.3);
  }
  if (evt.key == "Right" && !evt.pressed) {
    _element->setTurnCoeff(0.0);
  }
}


//----------------------------------------------------------------------------

ArRef<Controller> controller;


ArRef<Scheduler>
simulationInit(void)
{
  ArRef<Scheduler> sched=RealTimeScheduler::NEW(1e-3);
  
  if(ArSystem::getCommandLine().size() > 1){
    
    bool isServer = false;
    StlString mode = ArSystem::getCommandLine()[1];
    
    if(mode == "--server")
      isServer = true;
    
    if(isServer && ArSystem::getCommandLine().size() == 3)
    {
      cerr << "Creating server..." << endl;
      int port;
      if(strToInt(port,ArSystem::getCommandLine()[2]))
      {
        ArRef<Connector> connector = ConnectorServer::NEW(port);
        Manager::createManager(connector);
        
        //City Generator
        ArRef<City> cityGen = City::NEW();
        cityGen->setTransient(false);
        
        double sizeX=1500,sizeY=1500,maxSlenderness=0.6,roadWidth=25,sideWalkWidth=5;
        double buildingMinWidth=8;
        int nbBuildings=320;
        cityGen->buildCity(sizeX,sizeY,maxSlenderness,roadWidth,sideWalkWidth,
                           buildingMinWidth, nbBuildings);
        
        for(unsigned int i=0; i<cityGen->getBuildings().size(); i++)
          Manager::getInstance()->getEnvironment()->addElement(cityGen->getBuildings()[i]);
        
        Manager::getInstance()->getEnvironment()->addElement(cityGen);
      }
    }
    else if(!isServer && ArSystem::getCommandLine().size() == 4)
    {
      cerr << "Creating client..." << endl;
      int port;
      StlString serverName;
      if(strToInt(port,ArSystem::getCommandLine()[3]))
      {
        ArRef<Connector> connector = ConnectorClient::NEW(ArSystem::getCommandLine()[2], port);
        Manager::createManager(connector);
      }
    }
    else
    {
      cerr << "usage : " << ArSystem::getCommandLine()[0] << " --server nbPort" << endl << "  or  : " << ArSystem::getCommandLine()[0] << " --client hostName nbPort" << endl;
      exit(1);
    }
    
    
    // On charge les animations de AwesomeMan
    AwesomeMan::loadAnimationAndActionData("./models/AwesomeMan/AwesomeAnims.xml");
    
    
    // Création du controlleur
    controller = Controller::NEW();
    
  }
  else
  {
    cerr << "usage : " << ArSystem::getCommandLine()[0] << " --server nbPort" << endl << "  or  : " << ArSystem::getCommandLine()[0] << " --client hostName nbPort" << endl;
    exit(1);
  }
  
  return(sched);
}

int
main(int argc,
     char ** argv)
{
  ArSystem arevi(argc,argv);
  hLibInit();
  registerAwesomeClasses();
  Controller::REGISTER_CLASS();
  
  ArSystem::loadPlugin("Imlib2ImageLoader");
  ArSystem::loadPlugin("MagickImageLoader");
  ArSystem::loadPlugin("XmlParser");
  ArSystem::simulationLoop(&simulationInit);
  return(0);
}

